package xyz.yuanjilu.service.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.EndEvent;
import org.activiti.bpmn.model.ExclusiveGateway;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.bpmn.model.StartEvent;
import org.activiti.bpmn.model.UserTask;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.IdentityService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.identity.Group;
import org.activiti.engine.identity.User;
import org.activiti.engine.impl.persistence.entity.GroupEntity;
import org.activiti.engine.impl.persistence.entity.UserEntity;
import org.activiti.engine.repository.NativeProcessDefinitionQuery;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import xyz.yuanjilu.dao.BpmNodeRuleDao;
import xyz.yuanjilu.entity.BpmNodeRuleEntity;
import xyz.yuanjilu.entity.SysRoleEntity;
import xyz.yuanjilu.entity.SysUserEntity;
import xyz.yuanjilu.service.BPMService;
import xyz.yuanjilu.service.SysUserService;
import xyz.yuanjilu.utils.BPMConstant;
import xyz.yuanjilu.utils.JSONUtils;
import xyz.yuanjilu.utils.RRException;
import xyz.yuanjilu.service.SysRoleService;
import xyz.yuanjilu.service.SysUserRoleService;

@Service
public class BPMServiceImpl implements BPMService{
	Logger logger = LoggerFactory.getLogger(getClass());
	@Autowired
	private IdentityService identityService;
	@Autowired
	private SysUserService userService;
	@Autowired
	private SysRoleService SysRoleService;
	@Autowired
	private SysUserRoleService sysUserRoleService;
	@Autowired
    private RepositoryService repositoryService;
	@Autowired
    private RuntimeService runtimeService;
	@Autowired
    private ObjectMapper objectMapper;
	@Autowired
	private BpmNodeRuleDao bpmNodeRuleDao;
	
	@Override
	@PostConstruct//创建时初始化工作流的人员信息
	public void reflashIdentity() {
		logger.info("-----------------开始对接系统用户到工作流identity服务中---------------------");
		HashMap<String, Object> map = new HashMap<String, Object>();
		
		List<SysRoleEntity> queryList2 = SysRoleService.queryList(map);
		logger.info("对接角色到identity的组");
		for (SysRoleEntity sysRoleEntity : queryList2) {
			GroupEntity groupEntity = new GroupEntity();
			String groupId = sysRoleEntity.getRoleId().toString();
			Group singleResult = identityService.createGroupQuery().groupId(groupId).singleResult();
			if (singleResult==null) {
				groupEntity.setId(groupId);
				groupEntity.setName(sysRoleEntity.getRoleName());
				groupEntity.setType(sysRoleEntity.getRemark());
				identityService.saveGroup(groupEntity);
				if (logger.isDebugEnabled()) {
					logger.debug("添加identity的组："+JSONUtils.toJSONString(groupEntity));
				}
			}
		}
		
		logger.info("对接用户到identity的用户");
		List<SysUserEntity> queryList = userService.queryList(map);
		for (SysUserEntity sysUserEntity : queryList) {
			UserEntity user=new UserEntity();
			String userId = sysUserEntity.getUserId().toString();
			User singleResult = identityService.createUserQuery().userId(userId).singleResult();
			if (singleResult==null) {
				user.setId(userId);
				user.setFirstName(sysUserEntity.getUsername());
				user.setPassword(sysUserEntity.getPassword());
				user.setEmail(sysUserEntity.getEmail());
				//这里使用角色作为组
				identityService.saveUser(user);
				if (logger.isDebugEnabled()) {
					logger.debug("添加identity的用户："+JSONUtils.toJSONString(user));
				}
			}
			List<Long> queryRoleIdList = sysUserRoleService.queryRoleIdList(sysUserEntity.getUserId());
			for (Long long1 : queryRoleIdList) {
				identityService.deleteMembership(userId.toString(),  long1.toString());
				
				identityService.createMembership(userId.toString(), long1.toString());
			}
		}
		logger.info("-----------------完成对接系统用户到工作流identity服务中---------------------");
		
	}

  	@Override
    public  List<Map<String,String>> getModelNode(String modelId) throws Exception {
  	//转换
        JsonNode jsonNode = objectMapper.readTree(repositoryService.getModelEditorSource(modelId));
        BpmnModel bpmnModel = new BpmnJsonConverter().convertToBpmnModel(jsonNode);
        //取第一个流程,注：不包括子流程 待开发
        if(bpmnModel.getProcesses().size()<1){
            return null;
        }
        Process process = bpmnModel.getProcesses().get(0);
        return this.getModelNode(process);
    }
  	@Override
    public  List<Map<String,String>> getProcessDefinitionNode(String processDefinitionId) throws Exception {
  		BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        Process process = bpmnModel.getProcesses().get(0);
        return this.getModelNode(process);
    }
  	@Override
    public  List<Map<String,String>> getModelNode(Process process) throws Exception {
        String contextPath = "../";
        Collection<FlowElement> flowElements = process.getFlowElements();
        //取得其中关键数据
        List<Map<String,String>> lists=new ArrayList<>();
        Map<String,String> tempmap=null;
        Map<String, Map<String,String>> allmap=new HashMap<>();
        for (FlowElement flowElement : flowElements) {
            tempmap=new HashMap<>();
            tempmap.put("treeId", flowElement.getId());
            //tempmap.put("modelId", modelId);
            if(flowElement instanceof StartEvent){
                tempmap.put("treeName", "开始节点");
                tempmap.put("type", "1");
                tempmap.put("icon", contextPath+"/statics/images/sys/none.png");
            }else if(flowElement instanceof UserTask){
                tempmap.put("type", "2");
                tempmap.put("treeName",flowElement.getName());
                tempmap.put("icon", contextPath+"/statics/images/sys/typeuser.png");
            }else if(flowElement instanceof ExclusiveGateway){
                tempmap.put("type", "3");
                tempmap.put("treeName",flowElement.getName());
                tempmap.put("icon", contextPath+"/statics/images/sys/exclusive.png");
            } else if(flowElement instanceof SequenceFlow){
                tempmap.put("type", "4");
                tempmap.put("treeName",flowElement.getName());
                tempmap.put("icon", contextPath+"/statics/images/sys/sequenceflow.png");
            }else if(flowElement instanceof EndEvent){
                tempmap.put("type", "5");
                if(StringUtils.isNotEmpty(flowElement.getName())){
                    tempmap.put("treeName",flowElement.getName());
                }else{
                    tempmap.put("treeName","结束");
                }
                tempmap.put("icon", contextPath+"/statics/images/sys/endnone.png");
            }
            String pid="0";
            if(flowElement instanceof SequenceFlow){
                pid=((SequenceFlow) flowElement).getSourceRef();
                tempmap.put("tarid", ((SequenceFlow) flowElement).getTargetRef());
                lists.add(tempmap);
            }else{
                List<SequenceFlow> sqlist= ((FlowNode) flowElement).getIncomingFlows();
                if(sqlist!=null&&sqlist.size()>0){
                    SequenceFlow tem1=sqlist.get(0);
                    pid=tem1.getSourceRef();
                }
            }
            tempmap.put("treePid", pid);
            allmap.put(flowElement.getId(),tempmap);
        }
        for(Map<String,String> map:lists){
            String pid=map.get("treePid");
            //如果该元素的父节点不为空 ，且父节点是 分支类型的
            if(allmap.get(pid)!=null&&"3".equals(allmap.get(pid).get("type"))){
                allmap.get(map.get("tarid")).put("treePid", map.get("treeId"));
            }else{
                allmap.remove( map.get("treeId"));
            }
        }
        lists.clear();
        for (Map.Entry<String, Map<String, String>> entry : allmap.entrySet()) {
            String typex=entry.getValue().get("type");
            if("2".equals(typex)){
                entry.getValue().put("treePid", "0");
            }else if("1".equals(typex)){
                continue;
            }
            lists.add(entry.getValue());
        }
        return lists;
    }
  	
  	
    @Override
    public ResponseEntity<byte[]> showModelFlowImg(String modelId) {
        try {
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
            byte[] bytes = repositoryService.getModelEditorSourceExtra(modelId);
            return new ResponseEntity<byte[]>(bytes, headers, HttpStatus.CREATED);
        } catch (Exception e) {
            throw new RRException("流程图片加载失败!");
        }
    }

	@Override
	public List<BpmNodeRuleEntity> getModelNodeRule(String modelId, String nodeId) {
		return this.getModelNodeRule(modelId, nodeId, BPMConstant.MODEL_RULE_INIT_DEPLOYMENTID);
	}
	@Override
	public List<BpmNodeRuleEntity> getModelNodeRule(String modelId, String nodeId, String deploymentId) {
		
		Map<String ,String> param = new HashMap<String ,String>();
		param.put("modelId", modelId);
		param.put("nodeId", nodeId);
		param.put("bpmDeploymentId",deploymentId );
		param.put("sidx", "rule_order");
		param.put("order", "asc");
		
		return bpmNodeRuleDao.queryList(param);
	}
    
	@Override
	public List<BpmNodeRuleEntity> getProcessDefinitionNodeRule(String processDefinitionId) {
		
		return this.getProcessDefinitionNodeRule(processDefinitionId, null);
	}
	@Override
	public List<BpmNodeRuleEntity> getProcessDefinitionNodeRule(String processDefinitionId, String nodeId) {
		
		Map<String ,String> param = new HashMap<String ,String>();
		param.put("bpmProcessDefinitionId", processDefinitionId);
		param.put("nodeId", nodeId);
		param.put("sidx", "rule_order");
		param.put("order", "asc");
		
		return bpmNodeRuleDao.queryList(param);
	}

	@Override
	public void deploymentModelRule(String modelId, String deploymentId) {
			Map param = new HashMap();
			param.put("modelId", modelId);
			param.put("bpmDeploymentId", BPMConstant.MODEL_RULE_INIT_DEPLOYMENTID);
			param.put("sidx", "rule_order");
			param.put("order", "asc");
			List<BpmNodeRuleEntity> queryList = bpmNodeRuleDao.queryList(param);
			if (CollectionUtils.isEmpty(queryList)) {
				throw new RRException("模型没有配置节点规则");
			}
			
			/**
			 * 复制一份作为部署运行的配置信息
			 */
			String processDefinitionId = this.getProcessDefinitionId(deploymentId);
			for (BpmNodeRuleEntity bpmNodeRuleEntity : queryList) {
				bpmNodeRuleEntity.setId(bpmNodeRuleEntity.getId()+processDefinitionId);
				bpmNodeRuleEntity.setPid(bpmNodeRuleEntity.getPid()+processDefinitionId);
				bpmNodeRuleEntity.setBpmDeploymentId(deploymentId);
				bpmNodeRuleEntity.setBpmProcessDefinitionId(processDefinitionId);
				bpmNodeRuleDao.save(bpmNodeRuleEntity);
			}
	}

	public String getProcessDefinitionId(String deploymentId) {
		ProcessDefinitionQuery createProcessDefinitionQuery = repositoryService.createProcessDefinitionQuery();
		ProcessDefinition singleResult = createProcessDefinitionQuery.deploymentId(deploymentId).singleResult();
		return 	singleResult.getId();
	}

	@Override
	public List<BpmNodeRuleEntity> getRuntimeTaskButton(String processDefinitionId, String nodeId) throws Exception {
		Map param = new HashMap();
		param.put("bpmProcessDefinitionId", processDefinitionId);
		param.put("ruleType", BPMConstant.MODEL_RULE_TYPE_BUTTON);
		param.put("nodeId", nodeId);
		param.put("sidx", "rule_order");
		param.put("order", "asc");
		List<BpmNodeRuleEntity> queryList = bpmNodeRuleDao.queryList(param);
		if (CollectionUtils.isEmpty(queryList)) {
			throw new RRException("节点没有按钮规则");
		}
		return queryList;
	}

	@Override
	public List<BpmNodeRuleEntity> getRuntimeTaskButtonRule(String ruleId) throws Exception {
		Map param = new HashMap();
		param.put("pid", ruleId);
		param.put("sidx", "rule_order");
		param.put("order", "asc");
		List<BpmNodeRuleEntity> queryList = bpmNodeRuleDao.queryList(param);
		if (CollectionUtils.isEmpty(queryList)) {
			throw new RRException("按钮没有设置规则");
		}
		return queryList;
	}
	
	
	
    
}
